﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using EntityModel;
//using DynamicQueryable = System.Linq.Dynamic.DynamicQueryable;

namespace DataAccess.Extensions
{
    public static class IQueryableExtensions
    {
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
        {
            var type = typeof(T);
            var property = type.GetProperty(ordering);
            if (property == null)
            {
                return source;
            }

            var parameter = Expression.Parameter(type, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
            return source.Provider.CreateQuery<T>(resultExp);
        }

        public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string ordering, params object[] values)
        {
            var type = typeof(T);
            var property = type.GetProperty(ordering);
            if (property == null)
            {
                return source;
            }

            var parameter = Expression.Parameter(type, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
            return source.Provider.CreateQuery<T>(resultExp);
        }

        public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] includes) where T : class
        {
            return query.IncludeMultipleWithNoTracking(includes).AsNoTracking();
        }

        public static IQueryable<T> IncludeMultipleWithNoTracking<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] includes) where T : class
        {
            if (includes != null)
            {
                query = includes.Aggregate(query,
                          (current, include) =>
                          {
                              IQueryable<T> dbquery = current as DbQuery<T>;
                              if (dbquery == null)
                              {
                                  dbquery = current as ObjectQuery<T>;
                              }

                              return dbquery.Include(include);
                          });
            }

            return query;
        }

        public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, string path) where T : EntityBase
        {
            if (!string.IsNullOrEmpty(path))
            {
                query = query.Include(path);
            }

            return query;
        }

        /// <summary>
        /// Convert a queryable to a page view
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="orderBy"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        //public static List<T> ToPageView<T>(this IQueryable<T> query, string orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where T: class
        //{
        //    var numberOfSkipItems = (pageIndex - 1) * pageSize;

        //    query = DynamicQueryable.OrderBy(query, orderBy + " " + sortOrder.ToString());

        //    if (numberOfSkipItems > 0)
        //    {
        //        query = query.Skip(numberOfSkipItems);
        //    }

        //    if (pageSize > 0)
        //    {
        //        query = query.Take(pageSize);
        //    }

        //    return query.AsNoTracking().ToList();
        //}

        /// <summary>
        /// Ases the no tracking.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static IQueryable<T> NoTracking<T>(this IQueryable<T> source) where T : class
        {
            return source.AsNoTracking();
        }
        
    }
}
